using System;
using System.Collections.Generic;
using System.Text;
using ACS.Compiler.Tables;
using ACS.Compiler.Tables.Modes;
using ACS.Compiler.Tree.Interfaces;
using ACS.Compiler.Util;

namespace ACS.Compiler.Tree.Impl
{
    public class Slice : Expression, IFinalIdent
    {
        private Ident _from;
        private IExpression _index;

        public override void MatchSelect(Select select)
        {
            MatchExpression(select);
        }

        public override void MatchExpression(IExpression expression)
        {
            if (_from == null)
            {
                if (expression is Ident)
                {
                    _from = (Ident) expression;
                } else
                {
                    
                }
            } else
            {
                _index = expression;
            }  
        }

        public override void MatchCall(Call call)
        {
            MatchExpression(call);
        }

        public override void MatchIdent(Ident ident)
        {
            MatchExpression(ident);
        }

        public override Expressions ExpressionType
        {
            get { return Expressions.Slice; }
        }

        public Ident From
        {
            get { return _from; }
            set { _from = value; }
        }

        public IExpression Index
        {
            get { return _index; }
            set { _index = value; }
        }

        public override Mode Mode
        {
            get 
            { 
                return null;
            }
        }

        public override void Resolve(string ns, DataTable localData)
        {
        }

        public override string ToDeclareString()
        {
            return From.ToDeclareString() + "[" + Index.ToDeclareString() + "]";
        }

        public Mode ResolveIdent(string ns, DataTable localData, Mode parentMode)
        {
            Mode mode = null;
            if (parentMode == null)
            {
                Mode leftMode = From.ResolveIdent(ns, localData, null);
                ArrayMode leftArray = leftMode as ArrayMode;
                Array1Mode leftArray1 = leftMode as Array1Mode;
                if (leftArray !=null )
                {
                    mode = leftArray.Mode;
                } else
                {
                    if (leftArray1 != null)
                    {
                        mode = leftArray1.Mode;
                    } else
                    {
                        Logger.Instance.TraceError("Can't slice from non-array", this);
                    }
                }
            }
            else
            {
                ContainerMode parentContainer = parentMode as ContainerMode;
                if (parentContainer != null )
                {
                    mode = From.ModeResolveExpression(ns, localData, parentContainer);
                    ArrayMode m = mode as ArrayMode;
                    Array1Mode m1 = mode as Array1Mode;
                    if (m != null)
                    {
                        mode = m.Mode;
                    } else
                    {
                        if (m1 != null)
                        {
                            mode = m1.Mode;
                        } else
                        {
                            Logger.Instance.TraceError("Can't slice from non-array", this);
                        }
                    }
                } else
                {
                    Logger.Instance.TraceError("Can't slice from non-struct", this);
                }
            }
            Mode indexMode = Index.ModeResolveExpression(ns, localData, null);
            if (!ModesTable.Castable(indexMode, IntMode.Instance))
            {
                Logger.Instance.TraceModesNotEquals(indexMode, IntMode.Instance, this);
            }
            return mode;
        }
    }
}
